﻿using System.Reflection;
using System.Text;
using Ln.Fram.SqlSugarCore.Abstractions;
using Ln.Fram.SqlSugarCore.Repositories;
using Ln.Fram.SqlSugarCore.Uow;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.DependencyInjection.Extensions;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using SqlSugar;
using Volo.Abp.Data;
using Volo.Abp.Domain;
using Volo.Abp.Domain.Repositories;

namespace Ln.Fram.SqlSugarCore;

[DependsOn(typeof(AbpDddDomainModule))]
public class LnFramSqlSugarCoreModule : AbpModule
{
	public override Task ConfigureServicesAsync(ServiceConfigurationContext context)
	{
		var service = context.Services;
		var configuration = service.GetConfiguration();
		/* Lance:更改多数据源支持
		var section = configuration.GetSection("DbConnOptions");
		Configure<DbConnOptions>(section);
		*/
		// Lance:支持多数据源测试
		var section = configuration.GetSection("SqlSugarConnOptions");
		Configure<SqlSugarConnOptions>(section);
		service.TryAddScoped<ISqlSugarDbContext, SqlSugarDbContext>();
		//不开放sqlsugarClient
		//service.AddTransient<ISqlSugarClient>(x => x.GetRequiredService<ISqlsugarDbContext>().SqlSugarClient);
		service.AddTransient(typeof(IRepository<>), typeof(SqlSugarRepository<>));
		service.AddTransient(typeof(IRepository<,>), typeof(SqlSugarRepository<,>));
		service.AddTransient(typeof(ISqlSugarRepository<>), typeof(SqlSugarRepository<>));
		service.AddTransient(typeof(ISqlSugarRepository<,>), typeof(SqlSugarRepository<,>));
		service.AddTransient(typeof(ISugarDbContextProvider<>), typeof(UnitOfWorkSqlsugarDbContextProvider<>));
		//替换Sqlsugar默认序列化器，用来解决.Select()不支持嵌套对象/匿名对象的非公有访问器 值无法绑定,如Id属性
		context.Services.AddSingleton<ISerializeService, SqlSugarNonPublicSerializer>();
		/*
		var dbConfig = section.Get<DbConnOptions>();
		*/
		var dbConfig = section.Get<SqlSugarConnOptions>();
		//将默认db传递给abp连接字符串模块
		/*
		Configure<AbpDbConnectionOptions>(x => { x.ConnectionStrings.Default = dbConfig.Url; });
		*/
		Configure<AbpDbConnectionOptions>(x =>
		{
			x.ConnectionStrings.Default = dbConfig.DefaultLine.ConfigId;
			foreach (var line in dbConfig.LineList)
			{
				x.ConnectionStrings[line.ConfigId] = line.Url;
			}
		});
		return Task.CompletedTask;
	}

	public override async Task OnPreApplicationInitializationAsync(ApplicationInitializationContext context)
	{
		var service = context.ServiceProvider;
		var options = service.GetRequiredService<IOptions<SqlSugarConnOptions>>().Value;
		await OnPreApplicationInitializationAsync(context, options.DefaultLine);
		foreach (var line in options.LineList)
			await OnPreApplicationInitializationAsync(context, line);
	}

	private async Task OnPreApplicationInitializationAsync(ApplicationInitializationContext context, SqlSugarLineConnOptions line)
	{
		var service = context.ServiceProvider;
		var logger = service.GetRequiredService<ILogger<LnFramSqlSugarCoreModule>>();
		StringBuilder sb = new StringBuilder();
		sb.AppendLine();
		sb.AppendLine("==========Ln-SQL配置:==========");
		sb.AppendLine($"数据库连接电键：{line.ConfigId}");
		sb.AppendLine($"数据库连接字符串：{line.Url}");
		sb.AppendLine($"数据库类型：{line.DbType.ToString()}");
		sb.AppendLine($"是否开启种子数据：{line.EnabledDbSeed}");
		sb.AppendLine($"是否开启CodeFirst：{line.EnabledCodeFirst}");
		sb.AppendLine("===============================");
		logger.LogInformation(sb.ToString());
		//Todo：准备支持多租户种子数据及CodeFirst
		if (line.EnabledCodeFirst) CodeFirst(service);
		if (line.EnabledDbSeed) await DataSeedAsync(service);
	}

	private void CodeFirst(IServiceProvider service)
	{
		var moduleContainer = service.GetRequiredService<IModuleContainer>();
		var db = service.GetRequiredService<ISqlSugarDbContext>().SqlSugarClient;
		//尝试创建数据库
		db.DbMaintenance.CreateDatabase();
		var types = new List<Type>();
		foreach (var module in moduleContainer.Modules)
		{
			types.AddRange(module.Assembly.GetTypes()
				.Where(x => x.GetCustomAttribute<IgnoreCodeFirstAttribute>() == null)
				.Where(x => x.GetCustomAttribute<SugarTable>() != null)
				.Where(x => x.GetCustomAttribute<SplitTableAttribute>() is null));
		}
		if (types.Count > 0)
			db.CopyNew().CodeFirst.InitTables(types.ToArray());
	}

	private async Task DataSeedAsync(IServiceProvider service)
	{
		var dataSeeder = service.GetRequiredService<IDataSeeder>();
		await dataSeeder.SeedAsync();
	}
}